package cn.com.ry.framework.linklog.util;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ReflectUtil {

    public static boolean isPrimitiveWrapper(Class<?> clazz) {
        if (null == clazz) {
            return false;
        }
        return BasicType.WRAPPER_PRIMITIVE_MAP.containsKey(clazz);
    }

    public static boolean isBasicType(Class<?> clazz) {
        if (null == clazz) {
            return false;
        }
        return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
    }

    public static boolean isAllAssignableFrom(Class<?>[] types1, Class<?>[] types2) {
        if ((types1 == null || types1.equals("")) && (types2 == null || types2.equals(""))) {
            return true;
        }
        if (null == types1 || null == types2) {
            // 任何一个为null不相等（之前已判断两个都为null的情况）
            return false;
        }
        if (types1.length != types2.length) {
            return false;
        }

        Class<?> type1;
        Class<?> type2;
        for (int i = 0; i < types1.length; i++) {
            type1 = types1[i];
            type2 = types2[i];
            if (isBasicType(type1) && isBasicType(type2)) {
                // 原始类型和包装类型存在不一致情况
                if (BasicType.unWrap(type1) != BasicType.unWrap(type2)) {
                    return false;
                }
            } else if (false == type1.isAssignableFrom(type2)) {
                return false;
            }
        }
        return true;
    }

    public static Method getMethod(Class<?> clazz, String methodName, Class... paramTypes) throws SecurityException {
        Method[] methods = clazz.getDeclaredMethods();
        if (methods != null && methods.length > 0 && methodName != null && !methodName.equals("")) {
            for (Method method : methods) {
                String a_methodName = method.getName();
                if (a_methodName.equals(methodName)) {
                    if (isAllAssignableFrom(method.getParameterTypes(), paramTypes)) {
                        return method;
                    }
                }
            }
        }
        return null;
    }

    public enum BasicType {
        BYTE, SHORT, INT, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, CHAR, CHARACTER, STRING;

        /**
         * 包装类型为Key，原始类型为Value，例如： Integer.class =》 int.class.
         */
        public static final Map<Class<?>, Class<?>> WRAPPER_PRIMITIVE_MAP = new ConcurrentHashMap<>(8);
        /**
         * 原始类型为Key，包装类型为Value，例如： int.class =》 Integer.class.
         */
        public static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_MAP = new ConcurrentHashMap<>(8);

        static {
            WRAPPER_PRIMITIVE_MAP.put(Boolean.class, boolean.class);
            WRAPPER_PRIMITIVE_MAP.put(Byte.class, byte.class);
            WRAPPER_PRIMITIVE_MAP.put(Character.class, char.class);
            WRAPPER_PRIMITIVE_MAP.put(Double.class, double.class);
            WRAPPER_PRIMITIVE_MAP.put(Float.class, float.class);
            WRAPPER_PRIMITIVE_MAP.put(Integer.class, int.class);
            WRAPPER_PRIMITIVE_MAP.put(Long.class, long.class);
            WRAPPER_PRIMITIVE_MAP.put(Short.class, short.class);

            for (Map.Entry<Class<?>, Class<?>> entry : WRAPPER_PRIMITIVE_MAP.entrySet()) {
                PRIMITIVE_WRAPPER_MAP.put(entry.getValue(), entry.getKey());
            }
        }

        /**
         * 原始类转为包装类，非原始类返回原类
         *
         * @param clazz 原始类
         * @return 包装类
         */
        public static Class<?> wrap(Class<?> clazz) {
            if (null == clazz || false == clazz.isPrimitive()) {
                return clazz;
            }
            Class<?> result = PRIMITIVE_WRAPPER_MAP.get(clazz);
            return (null == result) ? clazz : result;
        }

        /**
         * 包装类转为原始类，非包装类返回原类
         *
         * @param clazz 包装类
         * @return 原始类
         */
        public static Class<?> unWrap(Class<?> clazz) {
            if (null == clazz || clazz.isPrimitive()) {
                return clazz;
            }
            Class<?> result = WRAPPER_PRIMITIVE_MAP.get(clazz);
            return (null == result) ? clazz : result;
        }
    }
}
